<script setup lang="ts">
  import { computed, ref } from 'vue'
  import { useStockStore } from '@/stores/stockStore'

  const stockStore = useStockStore()
  const selectCode = ref('')
  const selectWindow = ref('')
  const selectPeriod = ref('')
  const selectDate = ref('')
  const snackbarStatus = ref(false)
  const snackbarMes = ref('')
  const onHandleGetStockIntradayMovementWithDateBtnClick = async () => {
    snackbarMes.value = await stockStore.getStockIntradayMovementWithDate(selectCode.value, selectWindow.value, selectPeriod.value, selectDate.value)
    snackbarStatus.value = true
  }
  // 说明
  const informationDialogStatus = ref(false)
  const onInformationChipClick = () => {
    informationDialogStatus.value = true
  }
  // 判断是否显示Chart
  const is_showChart = computed(() => {
    const movement = stockStore.stockIntradayMovementWithDate

    const upper = movement.UpperBound ?? {}
    const lower = movement.LowerBound ?? {}
    const price = movement.IntradayPrice ?? {}

    const isUpperEmpty = Object.keys(upper).length === 0
    const isLowerEmpty = Object.keys(lower).length === 0
    const isPriceEmpty = Object.keys(price).length === 0

    // 全部为空
    const allEmpty = isUpperEmpty && isLowerEmpty && isPriceEmpty
    return !allEmpty
  })

  const optionChart = computed(() => {
    const movement = stockStore.stockIntradayMovementWithDate
    const upper = movement.UpperBound ?? {}
    const lower = movement.LowerBound ?? {}
    const price = movement.IntradayPrice ?? {}

    const times = Object.keys(upper)
    const upperData = times.map(t => upper[t])
    const lowerData = times.map(t => lower[t])
    const areaData = times.map(t => upper[t] - lower[t])
    const priceData = times.map(t => price[t])
    const allYValues: number[] = []

    for (const t of times) {
      const up = upper[t] ?? 0
      const low = lower[t] ?? 0
      const p = price[t]
      allYValues.push(up, low)
      if (p != null) allYValues.push(p)
    }

    // 自动计算 y 轴范围，加一点边距
    const minY = Math.min(...allYValues)
    const maxY = Math.max(...allYValues)
    const yPadding = (maxY - minY) * 0.1 || 0.5// 至少留 0.5 空间

    return {
      xAxis: {
        type: 'category',
        data: times,
        name: '时间',
        axisLabel: {
          fontSize: 14,
          color: '#FEFEFE',
          rotate: 45,
        },
        nameTextStyle: {
          fontSize: 14,
          color: '#FEFEFE',
          fontWeight: 'bold',
        },
      },
      yAxis: {
        type: 'value',
        name: '值',
        min: Math.round((minY - yPadding) * 100) / 100,
        max: Math.round((maxY + yPadding) * 100) / 100,
        axisLabel: {
          fontSize: 14,
          color: '#FEFEFE',
        },
        nameTextStyle: {
          fontSize: 14,
          color: '#FEFEFE',
          fontWeight: 'bold',
        },
        splitLine: {
          lineStyle: {
            type: 'dashed',
            color: '#ddd',
          },
        },
      },
      tooltip: {
        trigger: 'axis',
        formatter: (params: any[]) => {
          const time = params[0].axisValue
          const upperVal = upper[time]
          const lowerVal = lower[time]
          const priceVal = price[time]

          return `${time}<br/>
          <span style="color:#f56c6c;">●</span> 上边界: ${upperVal?.toFixed(4)}<br/>
          <span style="color:#67c23a;">●</span> 下边界: ${lowerVal?.toFixed(4)}<br/>
          <span style="color:#FFD700;">●</span> 当日价格: ${priceVal?.toFixed(4) ?? '—'}<br/>`
        },
      },
      legend: {
        data: ['平衡区域', '上边界', '下边界', '当日价格'],
        textStyle: {
          fontSize: 14,
          color: '#FEFEFE',
        },
        top: '5%',
      },
      series: [
        {
          name: '下边界（基准）',
          type: 'line',
          data: lowerData,
          stack: 'bound',
          legendHoverLink: false,
          lineStyle: { width: 0 },
          showSymbol: false,
          areaStyle: { opacity: 0 },
          color: '#67c23a', // 固定颜色
        },
        {
          name: '平衡区域',
          type: 'line',
          data: areaData,
          stack: 'bound',
          lineStyle: { width: 0 },
          showSymbol: false,
          areaStyle: {
            opacity: 0.3,
            color: '#42A5F5',
          },
          color: '#42A5F5',
        },
        {
          name: '上边界',
          type: 'line',
          data: upperData,
          lineStyle: { width: 2, color: '#f56c6c' },
          symbol: 'circle',
          color: '#f56c6c',
        },
        {
          name: '下边界',
          type: 'line',
          data: lowerData,
          lineStyle: { width: 2, color: '#67c23a' },
          symbol: 'circle',
          z: 10,
          color: '#67c23a',
        },
        {
          name: '当日价格',
          type: 'line',
          data: priceData,
          lineStyle: { width: 2, color: '#FFD700' },
          symbol: 'circle',
          z: 15,
          color: '#FFD700',
        },
      ],
      grid: {
        top: '20%',
        left: '10%',
        right: '10%',
        bottom: '15%',
      },
    }
  })
</script>

<template>
  <v-container>
    <v-row>
      <v-card
        class="w-100 ma-4"
        hover
        variant="outlined"
      >
        <template #subtitle>
          <v-container>
            <v-row>
              <text>日内动量数据</text>
              <v-spacer />
              <v-chip
                class="ml-2"
                prepend-icon="mdi-information"
                @click="onInformationChipClick"
              >
                说明
              </v-chip>
              <v-snackbar
                v-model="snackbarStatus"
              >
                {{ snackbarMes }}
                <template #actions>
                  <v-btn
                    color="pink"
                    variant="text"
                    @click="snackbarStatus = false"
                  >
                    Close
                  </v-btn>
                </template>
              </v-snackbar>
              <v-dialog
                v-model="informationDialogStatus"
                transition="dialog-bottom-transition"
                width="auto"
              >

                <v-card
                  prepend-icon="mdi-information"
                  title="日内动量(Intraday Movement)说明: "
                >
                  <template #text>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;此日内动量(Intraday Movement)的算法来源于<em>Carlo Zarattini1, Andrew Aziz2,3, Andrea Barbon的An Effective Intraday Momentum Strategy for S&P500 ETF (SPY)论文</em>, 针对高频周期内的动量分析。</p>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;在传统的技术分析中, 人们认为过去的股票表现不能预测未来的回报, 但是通过大数据的分析发现, 近期表现强劲的股票往往会在中短期内继续表现出色, 这可以解释为一种股票价格的持续趋势跟随行为, 这就是动量效应的发现, 而造成这种效应的原因, 普遍认为是对于新闻的反应不足, 导致信息被缓慢地吸收进价格中。</p>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;如果将这种效应应用于短期高频的股票技术分析中, 就可以通过股票在近期每一天的动量趋势来预测出股票的价格趋势, 如果股票在近期的动量趋势为上涨的趋势, 则可以认为股票的价格可能受到买家的推动而产生的趋势而上涨, 如果股票在近期的动量趋势为下跌的趋势, 则可以认为股票的价格可能受到卖家的推动而产生的趋势而下跌。</p>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;日内趋势的存在通常源于买卖双方在整个交易时段内持续的博弈抗衡, 为了将这种抗衡可以被量化, 需要使用数学化的方式去定义这种抗衡的情况。</p>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;该算法中认为当日的某个时间点的波动小于前几天在相同的日内时间间隔上观察到的平均波动时，市场表现出缺乏异常的不平衡, 在数学中定义了一个<em>噪声区(Noise Area)</em>去描述平衡的状态, 该区域由两条边界组成, 这些边界与时间有关, 是根据过去14天记录的平均运动来计算的, 计算方式如下: </p>
                    <p><img alt="" src="https://zhixuntrader-pic.oss-cn-shenzhen.aliyuncs.com/result.jpeg"></p>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;为了调整t+1市场中的<em>隔夜差距(overnight gaps)</em>, 还需要对两个边界进行调整: </p>
                    <p><img alt="" src="https://zhixuntrader-pic.oss-cn-shenzhen.aliyuncs.com/Snipaste_2025-07-04_16-32-32.png"></p>
                    <br>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>从结论来看,如果某个时刻的价格在两条边界之间的噪声区, 可以认为是在正常的波动区间内, 买家和卖家的力量平衡, 若突破了上边界, 可以考虑买入, 此时盘内存在买方压力, 可能推动股票上涨, 若突破了下边界, 可以考虑卖出, 此时盘内存在卖方压力, 可能会推动股票下跌。</strong></p>
                    <br>
                    <h2>参数说明: </h2>
                    <ul>
                      <li>
                        <strong>股票代码(code): 必填</strong> 填入需要获取日内动量数据的股票代码 如: <em>000421</em>
                      </li>
                      <li>
                        <strong>时间窗口(window): 选填 默认为14天</strong> 填入需要参考的日期时间窗口 如: <em>14</em>
                      </li>
                      <li>
                        <strong>周期(period): 选填 默认为15分钟 可选:<em>15 30</em></strong> 填入当日历史价格记录的时间间隔 如: <em>15</em>
                      </li>
                      <li>
                        <strong>日期(date): 必填</strong> 填入需要分析的日期 <strong>填入今天的日期无效 只能分析过去的日期 若需要实时分析今天的数据 需要到策略中的日内动量分析中去实时分析</strong>   格式有要求 如: <em>20250703</em>
                      </li>
                    </ul>
                    <br>
                    <h2>操作说明: </h2>
                    <ol>
                      <li>
                        按参数说明填入对应的参数
                      </li>
                      <li>
                        点击<strong>获取动量数据</strong>的按钮
                      </li>
                      <li>
                        在下方即可看到对应的图像分析结果
                        <p>
                          <img alt="" src="https://zhixuntrader-pic.oss-cn-shenzhen.aliyuncs.com/Snipaste_2025-07-04_12-38-09.png" width="800">
                        </p>
                      </li>
                    </ol>
                    <br>
                    <h2>分析说明: </h2>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;图像分为3条折线和一个蓝色区域, 对应着下边界，下边界，当日价格和平衡区域, 横轴为当日连续的时间间隔, 纵轴为价格, 折线的每一个点对应着相应时间的价格。</p>
                    <p>&nbsp;&nbsp;&nbsp;&nbsp;在平衡区域的价格内, 买卖双方的力量势均力敌, 处于相对平衡中, 上边界为买家突破的极限价格, 下边界为卖家突破的极限价格。
                      当对应时间的价格突破上边界时, 可以认为此时的买家力量大于卖家力量, 股票有着上涨的动量趋势; 反之, 当对应时间的价格跌破下边界时, 可以认为此时的卖家力量大于买家力量, 股票有着下跌的动量趋势。</p>
                    <br>
                    <h2>注意说明: </h2>
                    <ol>
                      <li>动量趋势的意思为<strong>在理想情况下</strong>股票价格有着向对应方向移动的加速度或力量, 并不意外着价格会立即的变化, 需要结合其他的数据进行综合的分析！</li>
                      <li>每个股票的价格与动量趋势以及每天的动量趋势的关联性的强弱都不同, 会存在同一只股票隔一天动量趋势突然变化或价格趋势突然变化的情况, 属于隔夜风险, 仅供参考!</li>
                      <li><strong>由于接口的限制, 获取的数据只有最近一个月内。</strong></li>
                      <li>更多的注意说明, 在策略的日内动量分析中会提到。</li>
                    </ol>
                    <br>
                    <h2><strong>按<em>ESC</em>退出此说明</strong></h2>
                  </template>
                </v-card>
              </v-dialog>
            </v-row>
          </v-container>
        </template>
        <v-form>
          <v-container>
            <v-row>
              <v-col>
                <v-text-field v-model="selectCode" label="股票代码" required variant="outlined" />
              </v-col>
              <v-col>
                <v-text-field v-model="selectWindow" label="时间窗口" required variant="outlined" />
              </v-col>
              <v-col>
                <v-text-field v-model="selectPeriod" label="周期" required variant="outlined" />
              </v-col>
              <v-col>
                <v-text-field v-model="selectDate" label="日期" required variant="outlined" />
              </v-col>
            </v-row>
            <v-row>
              <v-col class="d-flex justify-end align-center" cols="12">
                <v-btn prepend-icon="mdi-magnify" variant="outlined" @click="onHandleGetStockIntradayMovementWithDateBtnClick">获取动量数据</v-btn>
              </v-col>
            </v-row>
            <v-row v-if="is_showChart">
              <v-divider class="mt-4 mb-4" thickness="2" />
              <e-charts class="w-100" :option="optionChart" style="height: 500px;" />
            </v-row>
          </v-container>
        </v-form>
      </v-card>
    </v-row>
  </v-container>
</template>

<style scoped lang="scss">

</style>
